package com.fl.nettydemo.handler;

import com.fl.nettydemo.agreement.DataReport;
import com.fl.nettydemo.agreement.HeartBeat;
import com.fl.nettydemo.agreement.StartFrame;
import com.fl.nettydemo.agreement.testEnum;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.ssl.SslHandshakeCompletionEvent;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * Created by XiChuan on 2018-11-05.
 */
@Slf4j
@Component
@ComponentScan("com.fl.nettydemo.handler.*")
public class ServerHandler extends ChannelInboundHandlerAdapter {
    @Autowired
    private TransCodingUntil until;

    private AtomicInteger channelCount = new AtomicInteger(0); //通道数量


    /**
     * 读数据
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("read channel=" + ctx.channel() + ", total channel=" + channelCount);
        try {
            String val = String.valueOf(msg);
            System.out.println(msg);
//          byte[] bytes = ByteUntil.hexToByteArray(val);
            //取出功能码
            String substring = val.substring(6, 8);
            Integer sign = Integer.valueOf(substring, 16);
            List<String> list = tolist(val);
            System.out.println("sign:"+sign);
            TransType(sign, list,ctx);
            log.info("转义:{}", list);
            Channel channel = ctx.channel();

        } catch (Exception e) {
            // 抛弃收到的数据
            e.printStackTrace();
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    private void TransType(Integer sign, List<String> list,ChannelHandlerContext ctx) {
        if (sign == testEnum.HeartBeat.getSignType()) {
            HeartBeat heartBeat = until.CodeByHeartBeat(list);
            log.info("心跳对象:{}", heartBeat);
        } else if (sign == testEnum.StartFrame.getSignType()) {
            StartFrame startFrame = TransCodingUntil.CodeByStartFrame(list);
            log.info("起始帧对象:{}", startFrame);
        } else if (sign == testEnum.DataReport.getSignType()){
            DataReport dataReport = TransCodingUntil.CodeByDataReport(list,ctx);
            log.info("数据上报对象1:{}", dataReport);
        }else if (sign == testEnum.DataTest.getSignType()){
            HeartBeat heartBeat = until.CodeByHeartBeat(list);
            log.info("主站召测对象:{}", heartBeat);
        }
    }

    private List<String> tolist(String val) {
        List<String> list = new ArrayList<>();
        char[] chars = val.toCharArray();
        for (int i = 0; i < chars.length; i += 2) {
            String des = String.valueOf(chars[i]) + String.valueOf(chars[i + 1]);
            list.add(des);
        }
        return list;
    }

    /**
     * 心跳检测的超时时会触发
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                System.out.println("trigger channel =" + ctx.channel());
                ctx.close();  //如果超时，关闭这个通道
            }
        } else if (evt instanceof SslHandshakeCompletionEvent) {
            System.out.println("ssl handshake done");
            //super.userEventTriggered(ctx,evt);
        }
    }

    /**
     * 当通道活动时
     *
     * @param ctx
     * @throws Exception
     */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        channelCount.incrementAndGet();//当有新通道连接进来时，将通道数+1
        System.out.println("active channel=" + ctx.channel() + ", total channel=" + channelCount + ", id=" + ctx.channel().id().asShortText());

    }

    /**
     * 当通道不活动时
     *
     * @param ctx
     * @throws Exception
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //当通道关闭时，将通道数-1
        ctx.close();
        channelCount.decrementAndGet();
        System.out.println("inactive channel,channel=" + ctx.channel() + ", id=" + ctx.channel().id().asShortText());
    }

    /**
     * 异常获取
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("exception channel=" + ctx.channel() + " cause=" + cause); //如果不活跃关闭此通道
        ctx.close();
    }


}